#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/bitrev.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/blkdev.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/uio.h>
#include <linux/idr.h>
#include <linux/bsg.h>
#include <linux/slab.h>

#include<linux/of.h>
#include<linux/of_gpio.h>
#include<linux/gpio.h>
#include<linux/platform_device.h>
#include <linux/i2c.h> 
#include"ap3216c.h"

#define AP3216C_NUM 1
#define AP3216C_NAME "ap3216c"

struct AP3216C
{
    dev_t devid;
    int major;
    int minor;
    struct cdev ap3216c_cdev;
    struct class *class;
    struct device *device;
    struct i2c_client *client;
};

static struct AP3216C ap3216c;

/*Reads the register values in one transaction or returns a negative
 *	error code on failure.*/
static int ap3216c_readReg(struct i2c_client *client,u8 reg,u8 *buffer, int length)
{
    	struct i2c_msg msg[] = {
		{
			.addr = client->addr,
			.flags = 0,
			.len = 1,
			.buf = &reg,
		},
		{
			.addr = client->addr,
			.flags = I2C_M_RD,
			.len = length,
			.buf = buffer,
		},
	};
    return i2c_transfer(client->adapter, msg, 2);
}
static int ap3216c_writeReg(struct i2c_client *client,u8 reg,u8 *buffer, int length)
{
        u8 data[64];
        data[0]=reg;
        memcpy(&data[1],buffer,length);

    	struct i2c_msg msg[] = {
		{
			.addr = client->addr,
			.flags = 0,
			.len = length+1,
			.buf = data,
		},
	};
    return i2c_transfer(client->adapter, msg, 1);
}

static int ap3216c_readByte(struct i2c_client *client,u8 reg,u8 *buffer)
{
    return ap3216c_readReg(client,reg,buffer,1);
}
static int ap3216c_writeByte(struct i2c_client *client,u8 reg,u8 buffer)
{
    return ap3216c_writeReg(client,reg,&buffer,1);
}

static int ap3216c_release (struct inode * node, struct file *file)
{
    printk("release\r\n");
    return 0;
}
static int ap3216c_open (struct inode *node, struct file *file)
{
    printk("open\r\n");
    return 0;
}

static ssize_t ap3216c_write (struct file *file, const char __user *buffer, size_t size, loff_t *loff)
{
    printk("write\r\n");
    return 0;
}
static 	ssize_t ap3216c_read (struct file *file, char __user *buffer, size_t size, loff_t *loff)
{
    int i;
    u8 buff[6];
    for(i=0;i<6;i++)
    {
        ap3216c_readByte(ap3216c.client,AP3216C_IRDATALOW+i,&buff[i]);
    }
    if(copy_to_user(buffer,buff,6))
        return -1;
    return 0;
}
static const struct file_operations ap3216c_fop={
    .write=ap3216c_write,
    .read=ap3216c_read,
    .open = ap3216c_open,
    .release=ap3216c_release,
    .owner = THIS_MODULE,
};


static int ap3216c_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    u8 data = 0;
    int ret = 0;
	/* 初始化AP3216C */
    ret = ap3216c_writeByte(client,AP3216C_SYSTEMCONG,0x04);/* 复位  	*/
    mdelay(50);
    ret = ap3216c_writeByte(client,AP3216C_SYSTEMCONG,0X03);/* 开启ALS、PS+IR 		   	*/
    ret = ap3216c_readByte(client,AP3216C_SYSTEMCONG,&data);/* 读取刚刚写进去的0X03 */
	if(data == 0X03)
		printk("ap3216c is ready!\r\n");	/* AP3216C正常 	*/
	else 
		printk("ap3216c is error!\r\n");	/* AP3216C失败 	*/
    
    if(ret<0)
    {
        printk("transfer error!\r\n");
        return ret;
    }
    ap3216c.client=client;

    return 0;
}

static int ap3216c_i2c_remove(struct i2c_client *client)
{
    printk("remove success!\r\n"); 
    return 0;
}

static const struct of_device_id ap3216c_driver_ids[] = {
	{ .compatible = "xiao,ap3216c" },
	{ }
};
const struct i2c_device_id  ap3216c_id_table[]={
    // {"xiao,ap3216c", 0},
    // { }
};
static struct i2c_driver ap3216c_driver = {
	.driver = {
		.name = AP3216C_NAME,
		.owner = THIS_MODULE,
		.of_match_table = ap3216c_driver_ids,
	},
	.probe = ap3216c_i2c_probe,
    .remove = ap3216c_i2c_remove,
    .id_table = ap3216c_id_table,
};



static int __init ap3216c_init(void)
{
    int ret = 0;
    if(ap3216c.major)
    {
        ap3216c.devid = MKDEV(ap3216c.major,ap3216c.minor);
        ret = register_chrdev_region(ap3216c.devid,AP3216C_NUM,AP3216C_NAME);
    }
    else
    {
        ret = alloc_chrdev_region(&ap3216c.devid,0,AP3216C_NUM,AP3216C_NAME);
    }
    if(ret<0)
    {
        printk("register chrdev error!\r\n");
        goto free_register; 
    }
    ap3216c.major=MAJOR(ap3216c.devid);
    ap3216c.minor = MINOR(ap3216c.devid);
    printk("major:%d\r\nminor:%d\r\n",ap3216c.major,ap3216c.minor);


    cdev_init(&ap3216c.ap3216c_cdev,&ap3216c_fop);
    ret = cdev_add(&ap3216c.ap3216c_cdev,ap3216c.devid,AP3216C_NUM);
    if(ret<0)
    {
        printk("cdev add error!\r\n");
        goto free_cdev;
    }

    ap3216c.class = class_create(THIS_MODULE,AP3216C_NAME);
    if(IS_ERR(ap3216c.class))
    {
        printk("class creat error!\r\n");
        goto free_class;
    }

    ap3216c.device = device_create(ap3216c.class,NULL,ap3216c.devid,NULL,AP3216C_NAME);
    if(IS_ERR(ap3216c.device))
    {
        printk("device creat error!\r\n");
        goto free_device;
    }

  return  i2c_add_driver(&ap3216c_driver);


free_device:
    device_destroy(ap3216c.class,ap3216c.devid);
free_class:
    class_destroy(ap3216c.class);
free_cdev:
    cdev_del(&ap3216c.ap3216c_cdev);
free_register:
    unregister_chrdev_region(ap3216c.devid,AP3216C_NUM);
    return -1;
}

static void __exit ap3216c_exit(void)
{
    i2c_del_driver(&ap3216c_driver);
    device_destroy(ap3216c.class,ap3216c.devid);
    class_destroy(ap3216c.class);
    cdev_del(&ap3216c.ap3216c_cdev);
    unregister_chrdev_region(ap3216c.devid,AP3216C_NUM);
}

module_init(ap3216c_init);
module_exit(ap3216c_exit);
MODULE_ALIAS("xiao");
MODULE_LICENSE("GPL");
